/*
 * Copyright (C) 2006-2010 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */

package org.alfresco.jlan.smb.server;

import org.alfresco.jlan.server.filesys.DiskInfo;
import org.alfresco.jlan.server.filesys.SrvDiskInfo;
import org.alfresco.jlan.server.filesys.VolumeInfo;
import org.alfresco.jlan.smb.NTTime;
import org.alfresco.jlan.util.DataBuffer;
import org.alfresco.jlan.util.DataPacker;

/**
 * Disk information packer class.
 *
 * @author gkspencer
 */
class DiskInfoPacker {

  //	Disk information levels

  public static final int InfoStandard 		= 1;
  public static final int InfoVolume 			= 2;
  public static final int InfoFsVolume 		= 0x102;
  public static final int InfoFsSize 			= 0x103;
  public static final int InfoFsDevice 		= 0x104;
  public static final int InfoFsAttribute = 0x105;
  public static final int InfoCifsUnix		= 0x200;
  public static final int InfoMacFsInfo		= 0x301;
	public static final int InfoFullFsSize	= 0x3EF;

	//	Mac support flags

	public static final int MacAccessControl					= 0x0010;
	public static final int MacGetSetComments					= 0x0020;
	public static final int MacDesktopDbCalls					= 0x0040;
	public static final int MacUniqueIds							= 0x0080;
	public static final int MacNoStreamsOrMacSupport	= 0x0100;

  /**
   * Class constructor.
   */
  public DiskInfoPacker() {
    super();
  }

  /**
   * Pack the standard disk information, InfoStandard.
   *
   * @param info        SMBDiskInfo to be packed.
   * @param buf 				Buffer to pack the data into.
   */
  public final static void packStandardInfo(DiskInfo info, DataBuffer buf) {

    //  Information format :-
    //    ULONG   File system identifier, always 0 ?
    //    ULONG   Sectors per allocation unit.
    //    ULONG   Total allocation units.
    //    ULONG   Total available allocation units.
    //    USHORT  Number of bytes per sector.

    //  Pack the file system identifier, 0 = NT file system

		buf.putZeros(4);
//		buf.putInt(999);

    //  Pack the disk unit information

		buf.putInt(info.getBlocksPerAllocationUnit());
		buf.putInt((int)info.getTotalUnits());
		buf.putInt((int) info.getFreeUnits());
		buf.putShort(info.getBlockSize());
  }

  /**
   * Pack the volume label information, InfoVolume.
   *
   * @param info				Volume information
   * @param buf         Buffer to pack data into.
   * @param uni					Use Unicode strings if true, else use ASCII strings
   */
  public final static void packVolumeInfo(VolumeInfo info, DataBuffer buf, boolean uni) {

    //  Information format :-
    //    ULONG   Volume serial number
    //    UCHAR   Volume label length
    //    STRING  Volume label

    //  Pack the volume serial number

		buf.putInt(info.getSerialNumber());

    //  Pack the volume label length and string

		buf.putByte(info.getVolumeLabel().length());
		buf.putString(info.getVolumeLabel(), uni);
  }

  /**
   * Pack the filesystem size information, InfoFsSize
   *
   * @param info				Disk size information
   * @param buf         Buffer to pack data into.
   */
  public final static void packFsSizeInformation(SrvDiskInfo info, DataBuffer buf) {

  	//	Information format :-
  	//	 ULONG	Disk size (in units)
  	//	 ULONG	Free size (in units)
  	//	 UINT		Unit size in blocks
  	//	 UINT		Block size in bytes

		buf.putLong(info.getTotalUnits());
		buf.putLong(info.getFreeUnits());
		buf.putInt(info.getBlocksPerAllocationUnit());
		buf.putInt(info.getBlockSize());
  }

  /**
   * Pack the filesystem volume information, InfoFsVolume
   *
   * @param info			Volume information
   * @param buf       Buffer to pack data into.
   * @param uni				Use Unicode strings if true, else use ASCII strings
   */
  public final static void packFsVolumeInformation(VolumeInfo info, DataBuffer buf, boolean uni) {

  	//	Information format :-
  	//	 ULONG	Volume creation date/time (NT 64bit time fomat)
  	//	 UINT		Volume serial number
  	//	 UINT	 	Volume label length
  	//	 SHORT	Reserved
  	//	 STRING	Volume label (no null)

  	if ( info.hasCreationDateTime())
  		buf.putLong(NTTime.toNTTime(info.getCreationDateTime()));
  	else
  		buf.putZeros(8);

  	if ( info.hasSerialNumber())
  		buf.putInt(info.getSerialNumber());
  	else
  		buf.putZeros(4);

		int len = info.getVolumeLabel().length();
		if ( uni)
			len *= 2;
		buf.putInt(len);

		buf.putZeros(2);		//	reserved
		buf.putString(info.getVolumeLabel(), uni, false);
  }

  /**
   * Pack the filesystem device information, InfoFsDevice
   *
   * @param typ					Device type
   * @param devChar			Device characteristics
   * @param buf         Buffer to pack data into.
   */
  public final static void packFsDevice(int typ, int devChar, DataBuffer buf) {

  	//	Information format :-
  	//	 UINT		Device type
  	//	 UINT 	Characteristics

		buf.putInt(typ);
		buf.putInt(devChar);
  }

  /**
   * Pack the filesystem attribute information, InfoFsAttribute
   *
   * @param attr				Attribute flags
   * @param maxName			Maximum file name component length
   * @param fsType			File system type name
   * @param uni					Unicode strings required
   * @param buf         Buffer to pack data into.
   */
  public final static void packFsAttribute(int attr, int maxName, String fsType, boolean uni, DataBuffer buf) {

  	//	Information format :-
  	//	 UINT		Attribute flags
  	//	 UINT 	Maximum filename component length (usually 255)
  	//	 UINT		Filesystem type length
  	//	 STRING	Filesystem type string

		buf.putInt(attr);
		buf.putInt(maxName);

		if ( uni)
			buf.putInt(fsType.length() * 2);
		else
			buf.putInt(fsType.length());
		buf.putString(fsType, uni, false);
  }

  /**
   * Pack the Mac filesystem information, InfoMacFsInfo
   *
   * @param diskInfo    SMBDiskInfo to be packed.
   * @param volInfo			Volume information to be packed
   * @param ntfs				Filesystem supports NTFS streams
   * @param buf 				Buffer to pack the data into.
   */
  public final static void packMacFsInformation(DiskInfo diskInfo, VolumeInfo volInfo, boolean ntfs, DataBuffer buf) {

  	//	Information format :-
  	//		LARGE_INTEGER		Volume creation time (NT format)
  	//		LARGE_INTEGER		Volume modify time (NT format)
  	//		LARGE_INTEGER		Volume backup time (NT format)
  	//		ULONG						Allocation blocks
  	//		ULONG						Allocation block size (multiple of 512)
  	//		ULONG						Free blocks on the volume
  	//		UCHAR[32]				Finder info
  	//		LONG						Number of files in root directory (zero if unknown)
  	//		LONG						Number of directories in the root directory (zero if unknown)
  	//		LONG						Number of files on the volume (zero if unknown)
  	//		LONG						Number of directories on the volume (zero if unknown)
  	//		LONG						Mac support flags (big endian)

  	//	Pack the volume creation time

  	if ( volInfo.hasCreationDateTime()) {
  		long ntTime = NTTime.toNTTime(volInfo.getCreationDateTime());
  		buf.putLong(ntTime);
  		buf.putLong(ntTime);
  		buf.putLong(ntTime);
	  }
	  else
	  	buf.putZeros(24);

	  //	Pack the number of allocation blocks, block size and free block count

	  buf.putInt((int) diskInfo.getTotalUnits());
	  buf.putInt(diskInfo.getBlockSize() * diskInfo.getBlocksPerAllocationUnit());
	  buf.putInt((int)diskInfo.getFreeUnits());

  	//	Pack the finder information area

  	buf.putZeros(32);

  	//	Pack the file/directory counts

  	buf.putInt(0);
  	buf.putInt(0);
  	buf.putInt(0);
  	buf.putInt(0);

  	//	Pack the Mac support flags

		DataPacker.putIntelInt(ntfs ? 0 : MacNoStreamsOrMacSupport, buf.getBuffer(), buf.getPosition());
		buf.setPosition(buf.getPosition() + 4);
 	}

	/**
	 * Pack the filesystem size information, InfoFsSize
	 *
	 * @param userQuota User total units
	 * @param userLimit User free units
	 * @param info Disk size information
	 * @param buf Buffer to pack data into.
	 */
	public final static void packFullFsSizeInformation(long userTotalSpace, long userLimit, SrvDiskInfo info, DataBuffer buf) {

		//	 Information format :-
		//	 ULONG User total size (in units)
		//	 ULONG  User free size (in units)
		//	 ULONG	Free size (in units)
		//	 UINT		Unit size in blocks
		//	 UINT		Block size in bytes

		buf.putLong(userTotalSpace);
		buf.putLong(userLimit);
		buf.putLong(info.getFreeUnits());
		buf.putInt(info.getBlocksPerAllocationUnit());
		buf.putInt(info.getBlockSize());
	}
}
